/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using moose.extension;

namespace moose.irc
{
	/// <summary>
	/// This is an IRC Session
	/// </summary>
	[CLSCompliant(true)]
	public class IrcSession
	{

		#region [Local Attributes]
		
		/// <summary>
		/// Connection to IRC Server 
		/// </summary>
		private IrcConnection m_connection;
		
		/// <summary>
		/// Internal Address List 
		/// </summary>
		private IrcEntityList m_InternalAddressList;
		
		/// <summary>
		/// Current State 
		/// </summary>
		private IrcSessionStates m_currentState;

        /// <summary>
        /// Session Settings
        /// </summary>
        private Dictionary<IrcSessionSettings, object> m_session_settings;

        /// <summary>
        /// Server Settings
        /// </summary>
        private Dictionary<IrcServerSettings, object> m_server_settings;

		#endregion
		
		#region [Internal Properties]
		
		/// <summary>
		/// Provides a point of access for actions to affect
		/// the connection object directly.
		/// </summary>
		internal IrcConnection Connection {
			get {
				return m_connection;
			}
			set {
				m_connection = value;
				return;
			}
		}
		
		#endregion
		
		#region [Public Properties]
		
		/// <summary>
		/// Gets/Sets Current Session State
		/// </summary>
		public IrcSessionStates SessionState {
			get {
				return m_currentState;
			}
			set {
				m_currentState = value;
				return;
			}
		}

        /// <summary>
        /// Gets/Sets Server Settings
        /// </summary>
        public Dictionary<IrcServerSettings, object> Settings_Server
        {
            get
            {
                return m_server_settings;
            }
            set
            {
                m_server_settings = value;
                return;
            }
        }

        /// <summary>
        /// Gets/Sets Session Settings
        /// </summary>
        public Dictionary<IrcSessionSettings, object> Settings_Session
        {
            get
            {
                return m_session_settings;
            }
            set
            {
                m_session_settings = value;
                return;
            }
        }

		#endregion	
		
		#region [Events]
		
		/// <summary>
		///  Signal indicates an irc event
		/// </summary>
		public event IrcEventHandler Event;
		
		#endregion
		
		#region [Construction]
		
		/// <summary>
		/// Initialize IRC Session 
		/// </summary>
		public IrcSession() : base() {
			m_currentState = IrcSessionStates.Disconnected;
			m_connection = new IrcConnection();
			m_InternalAddressList = new IrcEntityList();

            m_server_settings = new Dictionary<IrcServerSettings, object>();
            m_session_settings = new Dictionary<IrcSessionSettings, object>();
			
			m_connection.Response += onServerResponse;
			Event += onIrcEvent;
			
			return;
		}
		
		#endregion
		
		#region [Public Methods]
		
		/// <summary>
		/// Send Data to server,
		/// actually, attempt to lookup a command and use that first. 
		/// </summary>
		/// <param name="message">
		/// A <see cref="System.String"/>
		/// Message/Command to send to the server
		/// </param>
		public void send(string input) {
			IrcMessage message = new IrcMessage(input);
			IrcAction action = ExtensionManager.get_action(ActionTypes.Command, message.Command);
			if (action == null)
				send_raw(input);
			else
				action.execute(this, message);
			return;
		}
		
		/// <summary>
		/// Send Data directly to the server, as-is,
		/// don't even attempt to find a command
		/// </summary>
		/// <param name="message">
		/// A <see cref="System.String"/>
		/// Message/Command to send to the server
		/// </param>
		public void send_raw(string message) {
			m_connection.send(message);
			return;
		}
		
		/// <summary>
		/// Gets/Looks-up IRC Entity, either a user or a channel
		/// </summary>
        /// <param name="entity_string">
		/// A <see cref="System.String"/>,
        /// this is either a channel name, a nickname or a BNF host string
		/// </param>
		/// <returns>
        /// A <see cref="IrcEntity"/>
		/// </returns>
		public IrcEntity get_entity(string entity_string) {
            return m_InternalAddressList.get(entity_string);
		}
		
		/// <summary>
		/// Notify of an Event 
		/// </summary>
		/// <param name="irc_event">
		/// A <see cref="IrcEvent"/>
		/// </param>
		public void notify_event(IrcEvent irc_event) {
			Event(this, irc_event);
			return;
		}
		
		#endregion
		
		#region [Event Handlers]
		
		/// <summary>
		/// Fires when server responds with a message of sorts 
		/// </summary>
		/// <param name="response">
		/// A <see cref="System.String"/>
		/// </param>
		private void onServerResponse(string response) {
            dispatch(new IrcMessage(response));
			return;
		}
		
		/// <summary>
		/// Handles IRC Events 
		/// </summary>
		/// <param name="session">
		/// A <see cref="IrcSession"/>
		/// </param>
		/// <param name="irc_event">
		/// A <see cref="IrcEvent"/>
		/// </param>
		private void onIrcEvent(IrcSession session, IrcEvent irc_event) {
			return;
		}
		
		#endregion

        #region [Message Processing]

        /// <summary>
        /// Process recieved message from server
        /// </summary>
        /// <param name="message">parsed message</param>
        private void dispatch(IrcMessage message)
        {
            if (message.Command == null) //If the message was not parsed correctly
                return; //Ignore it, quietly
            IrcAction action = ExtensionManager.get_action(ActionTypes.Response, message.Command);
            if (action != null)
            { //If a response-action has been found...
                action.execute(this, message); //execute that action
            }
            else
            {
                notify_event(IrcEvent.createEchoEvent(message.ToString()));
            }
            return;
        }

        #endregion

    }
}
